#include "sslserverthread.h"
#include <QFile>
#include <QSslConfiguration>
#include <QDir>
#include <QSslKey>
SSLServerThread::SSLServerThread(int socketDescriptor,QObject* parent) :
    QThread(parent)
{
    this->socketDescriptor=socketDescriptor;
    socket=new QSslSocket(this);
    runTimer=new QTimer(this);
    moveToThread(this);
}

SSLServerThread::~SSLServerThread()
{

}

int SSLServerThread::getSocketDescriptor() const
{
    return socket->socketDescriptor();
}

int SSLServerThread::getInitSocketDescriptor() const
{
    return socketDescriptor;
}
void SSLServerThread::run()
{
    if(!socket->setSocketDescriptor(socketDescriptor)){
        qWarning()<<"SSLServerThread::setSocketDescriptor:"<<socket->errorString();
        handleSocketDisconnected();
        return;
    }
#if 1
   /**
     The local certificate and private key are always necessary for server sockets,
     but are also rarely used by client sockets if the server requires the client to authenticate
     */

    socket->setPrivateKey("./localhost.key");               //私钥
    socket->setLocalCertificate("./localhost.cert");          //证书
#else
    QSslConfiguration sslConfiguration;
    QFile certFile(QStringLiteral("./localhost.cert"));
    QFile keyFile(QStringLiteral("./localhost.key"));
    qDebug()<<QDir::currentPath();
    if(certFile.open(QIODevice::ReadOnly)==false)
        qDebug()<<"can not open file";
    else
        qDebug()<<"key found";
    keyFile.open(QIODevice::ReadOnly);
    QSslCertificate certificate(&certFile, QSsl::Pem);
    QSslKey sslKey(&keyFile, QSsl::Rsa, QSsl::Pem);
    certFile.close();
    keyFile.close();
    sslConfiguration.setPeerVerifyMode(QSslSocket::VerifyNone);
    sslConfiguration.setLocalCertificate(certificate);
    sslConfiguration.setPrivateKey(sslKey);
    sslConfiguration.setProtocol(QSsl::TlsV1SslV3);
    socket->setSslConfiguration(sslConfiguration);
#endif
    //有数据接收
    connect(socket,SIGNAL(readyRead()),this,SLOT(datareceive()));
    //SSL握手完成
    connect(socket,SIGNAL(encrypted()),this,SLOT(handleSocketEncrypted()));
    //
    connect(socket,SIGNAL(modeChanged(QSslSocket::SslMode)),this,SLOT(handleSslModeChanged(QSslSocket::SslMode)));
    //普通连接成功
    connect(socket,SIGNAL(connected()),this,SLOT(handleSocketConnected()));
    //断开
    connect(socket,SIGNAL(disconnected()),this,SLOT(handleSocketDisconnected()));
    //打印socket状态
    connect(socket,SIGNAL(stateChanged(QAbstractSocket::SocketState)),this,SLOT(handleSocketStateChange(QAbstractSocket::SocketState)));
    //socket错误
    connect(socket,SIGNAL(error(QAbstractSocket::SocketError)),this,SLOT(handleSocketError(QAbstractSocket::SocketError)));
    //ssl错误
    connect(socket,SIGNAL(sslErrors(QList<QSslError>)),this,SLOT(handleSslErrorList(QList<QSslError>)),Qt::DirectConnection);
    //ssl错误
    connect(socket,SIGNAL(peerVerifyError(QSslError)),this,SLOT(handlePeerVerifyError(QSslError)));
    //开始加密
    qDebug()<<"startServerEncryption";
    socket->startServerEncryption();

    //定时发送数据
    runTimer->setInterval(1000);
    runTimer->setSingleShot(true);
    connect(runTimer,SIGNAL(timeout()),this,SLOT(_run()));
    runTimer->start();

    //启动QThread
    exec();
}

void SSLServerThread::_run()
{
    if(socket->isEncrypted()){
        socket->write("Hello from Server");
    }
    runTimer->start();
}

void SSLServerThread::datareceive()
{
    while(socket->bytesAvailable()>0){
        QByteArray data=socket->readAll();
        qDebug()<<"SSLServerThread::read:"<<data;
    }
}

void SSLServerThread::handleSocketEncrypted()
{
    //SSL握手成功
    qDebug()<<"SSLServerThread::handleSocketEncrypted";
}

void SSLServerThread::handleSslModeChanged(QSslSocket::SslMode mode)
{
    //
    switch(mode)
    {
    case QSslSocket::UnencryptedMode:
        qDebug()<<"SSLServerThread::handleSslModeChanged:"<<"UnencryptedMode";
        break;
    case QSslSocket::SslClientMode:
        qDebug()<<"SSLServerThread::handleSslModeChanged:"<<"SslClientMode";
        break;
    case QSslSocket::SslServerMode:
        qDebug()<<"SSLServerThread::handleSslModeChanged:"<<"SslServerMode";
        break;
    }
}

void SSLServerThread::handleSocketConnected()
{
    qDebug()<<"SSLServerThread::handleSocketConnected";
}

void SSLServerThread::handleSocketDisconnected()
{
    qDebug()<<"SSLServerThread::handleSocketDisconnected";
    runTimer->stop();
    requestDestroyed();
}
void SSLServerThread::requestDestroyed()
{
    if(socket->isOpen())
        socket->close();
    quit();
    emit socketDisconnected(socketDescriptor);
}

void SSLServerThread::handleSocketError(const QAbstractSocket::SocketError &socketError)
{
    qDebug()<<"SSLServerThread::handleSocketError:"<<socketError;
    switch(socketError)
        {
        case QAbstractSocket::ConnectionRefusedError:
            PrintMsg("The connection was refused by the peer (or timed out).");
            break;
        case QAbstractSocket::RemoteHostClosedError:
            PrintMsg("The remote host closed the connection. Note that the client socket (i.e., this socket) will be closed after the remote close notification has been sent.");
            break;
        case QAbstractSocket::HostNotFoundError:
            PrintMsg("The host address was not found.");
            break;
        case QAbstractSocket::SocketAccessError:
            PrintMsg("The socket operation failed because the application lacked the required privileges.");
            break;
        case QAbstractSocket::SocketResourceError:
            PrintMsg("The local system ran out of resources (e.g., too many sockets).");
            break;
        case QAbstractSocket::SocketTimeoutError:
            PrintMsg("The socket operation timed out.");
            break;
        case QAbstractSocket::DatagramTooLargeError:
            PrintMsg("The datagram was larger than the operating system's limit (which can be as low as 8192 bytes).");
            break;
        case QAbstractSocket::NetworkError:
            PrintMsg("An error occurred with the network (e.g., the network cable was accidentally plugged out).");
            break;
        case QAbstractSocket::AddressInUseError:
            PrintMsg("The address specified to bind() is already in use and was set to be exclusive.");
            break;
        case QAbstractSocket::SocketAddressNotAvailableError:
            PrintMsg("The address specified to bind() does not belong to the host.");
            break;
        case QAbstractSocket::UnsupportedSocketOperationError:
            PrintMsg("The requested socket operation is not supported by the local operating system (e.g., lack of IPv6 support).");
            break;
        case QAbstractSocket::ProxyAuthenticationRequiredError:
            PrintMsg("The socket is using a proxy, and the proxy requires authentication.");
            break;
        case QAbstractSocket::SslHandshakeFailedError:
            PrintMsg("The SSL/TLS handshake failed, so the connection was closed (only used in SslSocket)");
            break;
        case QAbstractSocket::UnfinishedSocketOperationError:
            PrintMsg("Used by AbstractSocketEngine only, The last operation attempted has not finished yet (still in progress in the background).");
            break;
        case QAbstractSocket::ProxyConnectionRefusedError:
            PrintMsg("Could not contact the proxy server because the connection to that server was denied");
            break;
        case QAbstractSocket::ProxyConnectionClosedError:
            PrintMsg("The connection to the proxy server was closed unexpectedly (before the connection to the final peer was established)");
            break;
        case QAbstractSocket::ProxyConnectionTimeoutError:
            PrintMsg("The connection to the proxy server timed out or the proxy server stopped responding in the authentication phase.");
            break;
        case QAbstractSocket::ProxyNotFoundError:
            PrintMsg("The proxy address set with setProxy() (or the application proxy) was not found.");
            break;
        case QAbstractSocket::ProxyProtocolError:
            PrintMsg("The connection negotiation with the proxy server because the response from the proxy server could not be understood.");
            break;
        case QAbstractSocket::UnknownSocketError:
            PrintMsg("An unidentified error occurred.");
            break;
        default:
            PrintMsg("Not match any errors.");
            break;
        }
}

void SSLServerThread::handleSslErrorList(const QList<QSslError> &errorList)
{
    qDebug()<<"SSLServerThread::handleSslErrorList";
    for(int i=0;i<errorList.count();i++)
    {
        handleSslError(errorList.at(i));
    }
}

void SSLServerThread::handlePeerVerifyError(const QSslError &error)
{
    qDebug()<<"SSLServerThread::handlePeerVerifyError";
    handleSslError(error);
}

void SSLServerThread::handleSslError(const QSslError &error)
{
    qDebug()<<"SSLServerThread::handleSslError:"<<error;
}


void SSLServerThread::handleSocketStateChange(const QAbstractSocket::SocketState &socketState)
{
    //UnconnectedState
    //HostLookupState
    //ConnectingState
    //BoundState
    //ClosingState
    //ListeningState

    qDebug()<<"SSLServerThread::handleSocketStateChange:"<<socketState;
    switch(socketState)
    {
    case QAbstractSocket::UnconnectedState:
        PrintMsg("Server:  The socket is not connected");
        break;
    case QAbstractSocket::HostLookupState:
        PrintMsg("Server:  The socket is performing a host name lookup");
        break;
    case QAbstractSocket::ConnectingState:
        PrintMsg("Server:  The socket has started establishing a connection");
        break;
    case QAbstractSocket::BoundState:
        PrintMsg("Server:  The socket is bound to an address and port (for servers).");
        break;
    case QAbstractSocket::ClosingState:
        PrintMsg("Server:  The socket is about to close (data may still be waiting to be written).");
        break;
    case QAbstractSocket::ListeningState:
        PrintMsg("Server:  ListeningState .For internal use only.");
        break;
    default:
        PrintMsg("Server:  Not match any states.");
        break;
    }
}
void SSLServerThread::PrintMsg(const char*msg)
{
    qDebug()<<msg;
}
